package com.hmall.common.utils;

import cn.hutool.core.lang.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.util.concurrent.ListenableFutureCallback;

@RequiredArgsConstructor
@Slf4j
public class RabbitMqHelper {
    private final RabbitTemplate rabbitTemplate;

    public void sendMessage(String exchange, String routingKey, Object msg) {
        log.debug("准备发送消息，exchange:{}, routingKey:{}, msg:{}", exchange, routingKey, msg);
        rabbitTemplate.convertAndSend(exchange, routingKey, msg);
    }

    public void sendDelayMessage(String exchange, String routingKey, Object msg, int delay) {
        rabbitTemplate.convertAndSend(exchange, routingKey, msg, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setDelay(10000);//延迟时间(毫秒),不要太长
                return message;
            }
        });
    }

    public void sendMessageWithConfirm(String exchange, String routingKey, Object msg, int maxRetries) {
        log.debug("准备发送消息，exchange:{}, routingKey:{}, msg:{}", exchange, routingKey, msg);
        CorrelationData cd = new CorrelationData(UUID.randomUUID().toString());
        cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
            int retryCount = 0;//这里的callback对象只有这一个,所以属性的改变会保留

            @Override
            public void onFailure(Throwable ex) {
                //失败后回调,这个mq内部问题,一般不会出现
                log.error("处理ack回执失败", ex);
            }

            @Override
            public void onSuccess(CorrelationData.Confirm result) {
                if (result != null && result.isAck()) {
                    log.debug("消息发送失败,已重试次数{}", retryCount);
                    if (retryCount > 3) {
                        log.error("重试次数到达3次上限");
                    }
                    CorrelationData cd = new CorrelationData(UUID.randomUUID().toString());
                    cd.getFuture().addCallback(this);//这里的this是指callback对象
                    //重试次数加1
                    retryCount++;
                    rabbitTemplate.convertAndSend(exchange, routingKey, msg, cd);
                }
            }
        });
        rabbitTemplate.convertAndSend(exchange, routingKey, msg, cd);
    }

}
